#include "overview.h"
#include "ui_overview.h"

#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QInputDialog>
Overview::Overview(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::Overview)
{
    ui->setupUi(this);
}

Overview::~Overview()
{
    delete ui;
}

void Overview::refreshStu() {
    ui->stuListWid->clear();
    QString queryText = ui->queryStuEdit->text();
    foreach(Student student,students)
        if(student.id.contains(queryText) || student.name.contains(queryText))
            ui->stuListWid->addItem(student.id + "," + student.name);
}

QStringList Overview::ActivityTypeNames(ActivityType type) {
    QStringList typeNames;
    if(type==noneType) typeNames.append(tr("None"));
    if(type&studentWork) typeNames.append(tr("Student Work"));
    if(type&personalDevelopment) typeNames.append(tr("Personal Development"));
    if(type&practiceVisit) typeNames.append(tr("Practice and Visit"));
    if(type&voluntaryActivity) typeNames.append(tr("Voluntary Activity"));
    if(type&communityLife) typeNames.append(tr("Community Life"));
    return typeNames;
}

void Overview::refreshAct() {
    refreshActList();
    ui->recListWid->clear();
    ui->recTableWid->clearContents();

    if(activities.contains(curActName)) {
        Activity curAct = activities[curActName];
        ui->actNameEdit->setText(curAct.name);
        ui->actTypeStuWork->setCheckState(curAct.type&studentWork?Qt::Checked:Qt::Unchecked);
        ui->actTypePerDev->setCheckState(curAct.type&personalDevelopment?Qt::Checked:Qt::Unchecked);
        ui->actTypeVolAct->setCheckState(curAct.type&voluntaryActivity?Qt::Checked:Qt::Unchecked);
        ui->actTypePracVis->setCheckState(curAct.type&practiceVisit?Qt::Checked:Qt::Unchecked);
        ui->actTypeComLife->setCheckState(curAct.type&communityLife?Qt::Checked:Qt::Unchecked);
        ui->actTypeAll->setCheckState(curAct.type==allType?Qt::Checked:(curAct.type?Qt::PartiallyChecked:Qt::Unchecked));
        ui->recListWid->addItems(curAct.records.keys());
        if(activities[curActName].records.contains(curRecName)) {
            ui->recNameEdit->setText(curRecName);
            Activity::ActivityRecord record = activities[curActName].records[curRecName];
            QStringList idList = record.keys();
            ui->recTableWid->setRowCount(idList.size());
            for(int index=0;index<idList.size();index++) {
                QString id=idList[index];
                ui->recTableWid->setItem(index,0,new QTableWidgetItem(id));
                if(students.contains(id))
                    ui->recTableWid->setItem(index,1,new QTableWidgetItem(students[id].name));
                ui->recTableWid->setItem(index,2,new QTableWidgetItem(ActivityTypeNames(record[id].second).join("|")));
                ui->recTableWid->setItem(index,3,new QTableWidgetItem(QString::number(record[id].first)));
            }
        } else {
            curRecName = {};
            ui->recNameEdit->clear();
            ui->actStackedWidget->setCurrentIndex(0);
        }
    } else {
        curActName = {};
        curRecName = {};
        ui->actNameEdit->clear();
        ui->actTypeStuWork->setCheckState(Qt::Unchecked);
        ui->actTypePerDev->setCheckState(Qt::Unchecked);
        ui->actTypeVolAct->setCheckState(Qt::Unchecked);
        ui->actTypePracVis->setCheckState(Qt::Unchecked);
        ui->actTypeComLife->setCheckState(Qt::Unchecked);
        ui->actTypeAll->setCheckState(Qt::Unchecked);
        ui->actStackedWidget->setCurrentIndex(0);
        ui->recNameEdit->clear();
    }
    ui->creditSpBox->setValue(10);
    recCheckState = allType;
    updateRecCheckState();
    ui->paIDNameEdit->clear();
}

void Overview::refreshActList() {
    ui->actListWid->clear();
    foreach(QString actName,activities.keys())
        if(actName.contains(ui->actNameQueryEdit->text()))
            ui->actListWid->addItem(actName);
}

void Overview::refreshDat() {
    QList<Student> stuList;
    QString queryText=ui->creditQueryEdit->text();
    foreach(Student student,students.values()) {
        if(student.id.contains(queryText) || student.name.contains(queryText))
            stuList.append(student);
    }
    QList<Activity> actList = activities.values();
    ui->creditTableWid->setRowCount(stuList.size());
    for(int index=0;index<stuList.size();index++) {
        Student student = stuList[index];
        ui->creditTableWid->setItem(index,0,new QTableWidgetItem(student.id));
        ui->creditTableWid->setItem(index,1,new QTableWidgetItem(student.name));
        unsigned total = getTotalCredits(student, actList);
        categoryCreditStatus status = checkTypeStatus(student, actList);
        bool qualified = (total>=fullCredit && status.qualification()==allType);
        ui->creditTableWid->setItem(index,2,new QTableWidgetItem(qualified?tr("qualified"):tr("not qualified")));
        ui->creditTableWid->setItem(index,3,new QTableWidgetItem(QString::number(total)));
        ui->creditTableWid->setItem(index,4,new QTableWidgetItem(QString::number(status.stuWork)));
        ui->creditTableWid->setItem(index,5,new QTableWidgetItem(QString::number(status.perDev)));
        ui->creditTableWid->setItem(index,6,new QTableWidgetItem(QString::number(status.volAct)));
        ui->creditTableWid->setItem(index,7,new QTableWidgetItem(QString::number(status.pracVis)));
        ui->creditTableWid->setItem(index,8,new QTableWidgetItem(QString::number(status.comLife)));
    }
    updateRecordView();
}

void Overview::refreshOview(const unsigned spacing) {
    QList<Student> stuList = students.values();
    QList<Activity> actList = activities.values();

    ui->stuWorkWid->clear();
    ui->perDevWid->clear();
    ui->volActWid->clear();
    ui->pracVisWid->clear();
    ui->comLifeWid->clear();
    ui->noneWid->clear();

    foreach(Activity activity,actList) {
        if(activity.type==noneType) ui->noneWid->addItem(activity.name);
        if(activity.type&studentWork) ui->stuWorkWid->addItem(activity.name);
        if(activity.type&personalDevelopment) ui->perDevWid->addItem(activity.name);
        if(activity.type&voluntaryActivity) ui->volActWid->addItem(activity.name);
        if(activity.type&practiceVisit) ui->pracVisWid->addItem(activity.name);
        if(activity.type&communityLife) ui->comLifeWid->addItem(activity.name);
    }

    unsigned total = students.size();
    if(total == 0u) return;
    unsigned Qua=0,Tot=0,SW=0,PD=0,VA=0,PV=0,CL=0;
    unsigned maxCredit = 0;
    QList<unsigned> creditList;

    for(int index=0;index<stuList.size();index++) {
        Student student = stuList[index];
        unsigned total = getTotalCredits(student, actList);
        categoryCreditStatus status = checkTypeStatus(student, actList);
        bool qualified = (total>=fullCredit && status.qualification()==allType);
        if(qualified) Qua++;
        if(total>=fullCredit) Tot++;
        if(status.stuWork>=categoryCredit) SW++;
        if(status.perDev>=categoryCredit) PD++;
        if(status.pracVis>=categoryCredit) PV++;
        if(status.volAct>=categoryCredit) VA++;
        if(status.comLife>=categoryCredit) CL++;
        creditList.append(total);
        maxCredit=qMax(maxCredit,total);
    }

    ui->QuaProg->setMinimum(0);
    ui->QuaProg->setMaximum(total);
    ui->QuaProg->setValue(Qua);
    ui->TotProg->setMinimum(0);
    ui->TotProg->setMaximum(total);
    ui->TotProg->setValue(Tot);
    ui->SWProg->setMinimum(0);
    ui->SWProg->setMaximum(total);
    ui->SWProg->setValue(SW);
    ui->PDProg->setMinimum(0);
    ui->PDProg->setMaximum(total);
    ui->PDProg->setValue(PD);
    ui->VAProg->setMinimum(0);
    ui->VAProg->setMaximum(total);
    ui->VAProg->setValue(VA);
    ui->PVProg->setMinimum(0);
    ui->PVProg->setMaximum(total);
    ui->PVProg->setValue(PV);
    ui->CLProg->setMinimum(0);
    ui->CLProg->setMaximum(total);
    ui->CLProg->setValue(CL);

    if(spacing==0) return;
    ui->distWid->setRowCount(maxCredit/spacing+1);
    for(unsigned index=0;index<=maxCredit/spacing;index++) {
        unsigned lb=index*spacing,ub=(index+1)*spacing-1;
        ui->distWid->setItem(index,0,new QTableWidgetItem(QString::number(lb)+"~"+QString::number(ub)));
        unsigned cnt=0,sum=0;
        foreach(unsigned credit,creditList) {
            if(credit<=ub) {
                sum++;
                if(credit>=lb) cnt++;
            }
        }
        ui->distWid->setItem(index,1,new QTableWidgetItem(QString::number(cnt)));
        ui->distWid->setItem(index,2,new QTableWidgetItem(QString::number(sum)));
        ui->distWid->setItem(index,3,new QTableWidgetItem(QString::number(sum*100/total)+"%"));
    }
}

void Overview::on_overviewTabWid_currentChanged(int index)
{
    if(index == 0) refreshStu();
    if(index == 1) refreshAct();
    if(index == 2) refreshDat();
    if(index == 3) refreshOview(10);
}

void Overview::on_homeBtn_clicked()
{
    if(home && home!=nullptr)
        home->show();
    this->destroy();
}


void Overview::on_saveBtn_clicked()
{
    QFile localData("data.enc.txcs");
    if(!localData.open(QFile::WriteOnly | QFile::Truncate)) return;
    QJsonObject object;
    object.insert("students",Student::getArr(students.values()));
    object.insert("activities",Activity::getArr(activities.values()));
    QJsonDocument doc;
    doc.setObject(object);

    localData.write(encrypt(doc.toJson(QJsonDocument::Compact)));
    localData.close();

    QFile studentData("data.encstu.txcs");
    if(!studentData.open(QFile::WriteOnly | QFile::Truncate)) return;
    object = QJsonObject();
    object.insert("students",Student::getArr(students.values(), true, true));
    object.insert("activities",Activity::getArr(activities.values()));
    doc.setObject(object);
    studentData.write(encrypt(doc.toJson(QJsonDocument::Compact),true));
    studentData.close();

    object = QJsonObject();
    object.insert("students",Student::getArr(students.values(),false));
    doc.setObject(object);

    QFile studentList("stulist.enc.txcs");
    if(!studentList.open(QFile::WriteOnly | QFile::Truncate)) return;
    studentList.write(encrypt(doc.toJson(QJsonDocument::Compact)));
    studentList.close();
}


void Overview::on_queryStuEdit_textChanged(const QString &arg1)
{
    ui->stuListWid->clear();
    foreach(Student student,students)
        if(student.id.contains(arg1) || student.name.contains(arg1))
            ui->stuListWid->addItem(student.id + "," + student.name);
}


void Overview::on_addStuBtn_clicked()
{
    QString info = QInputDialog::getText(this, tr("Information input"),tr("Input ID and name (format: <ID>,<name>[,<password>])"));
    info.replace("，",",");
    QStringList list = info.split(",");
    if(list.size()<2)
        return;
    if(!isValidId(list[0]))
        return;
    if(list[1].isEmpty())
        return;
    students[list[0]] = {list[0],list[1],{}};
    if(list.size()==3)
        if(isValidPwd(list[2])) students[list[0]] = {list[0],list[1],list[2]};
    refreshStu();
}


void Overview::on_remStuBtn_clicked()
{
    foreach(QListWidgetItem* item,ui->stuListWid->selectedItems()) {
        QString id=item->text().split(",")[0];
        if(students.contains(id))
            students.remove(id);
    }
    refreshStu();
}


void Overview::on_importStuBtn_clicked()
{
    QStringList stuList = ui->importStuEdit->toPlainText().split("\n");
    ui->importStuEdit->clear();
    foreach(QString stu,stuList) {
        stu.replace("，",",");
        QStringList list = stu.split(",",Qt::SplitBehaviorFlags::SkipEmptyParts);
        if(list.size()<2)
            continue;
        if(!isValidId(list[0]))
            continue;
        if(list[1].isEmpty())
            continue;
        students[list[0]] = {list[0],list[1],{}};
        if(list.size()==3)
            if(isValidPwd(list[2])) students[list[0]] = {list[0],list[1],list[2]};
    }
    refreshStu();
}


void Overview::on_newActBtn_clicked()
{
    QString name = QInputDialog::getText(this, tr("Name input"),tr("Input activity name"));
    if(activities.contains(name))
        return;
    if(!name.isEmpty())
        activities[name]=Activity(name);
    refreshAct();
}


void Overview::on_impActBtn_clicked()
{
    QStringList filePaths = QFileDialog::getOpenFileNames(this,tr("Select activity record file"),"",tr("Activity record (*.actrec)"));
    foreach(QString Path,filePaths) {
        Activity activity;
        if(Path.isEmpty())
            return;
        QFile inf(Path);
        if(!inf.open(QIODevice::ReadOnly)) {
            QMessageBox::warning(this,tr("warning"),tr("Failed while opening activity record:") + '\n' + Path);
            return;
        }
        QByteArray byteArray=decrypt(inf.readAll());
        inf.close();

        QJsonParseError parseError;
        QJsonDocument doc = QJsonDocument::fromJson(byteArray,&parseError);
        if (doc.isEmpty() || parseError.error != QJsonParseError::NoError) {
            QMessageBox::warning(this,tr("warning"),tr("Failed while parsing activity record:") + '\n' + Path);
            return;
        }
        QJsonObject object = doc.object();
        if(!activity.parseObj(object)) {
            QMessageBox::warning(this,tr("warning"),tr("Failed while parsing activity record:") + '\n' + Path);
            return;
        }

        if(activities.contains(activity.name)) {
            QMessageBox::StandardButton merge = QMessageBox::warning(this,
                                                                     tr("Merge Comfirmation"),
                                                                     tr("Are you sure to merge into activity:") +
                                                                         "    " + activity.name +'\n' +
                                                                         tr("This operation is not invokable!"),
                                                                     QMessageBox::Ok|QMessageBox::Cancel);
            if(merge!=QMessageBox::Cancel)
                activities[activity.name].merge(activity);
        } else
            activities[activity.name] = activity;
    }
    refreshAct();
}


void Overview::on_remActBtn_clicked()
{
    QList<QListWidgetItem*> itemList = ui->actListWid->selectedItems();
    foreach(QListWidgetItem* item,itemList) {
        if(activities.contains(item->text()))
            activities.remove(item->text());
    }
    refreshAct();
}


void Overview::on_actListWid_itemDoubleClicked(QListWidgetItem *item)
{
    curActName = item->text();
    refreshAct();
}


void Overview::on_actNameEdit_editingFinished()
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    QString newActName = ui->actNameEdit->text();
    if(newActName==curActName)
        return;
    if(newActName.isEmpty()) {
        ui->actNameEdit->setText(curActName);
        return;
    }
    if(!activities.contains(newActName)) {
        Activity copy = activities[curActName];
        activities.remove(curActName);
        curActName=newActName;
        copy.name=curActName;
        activities[curActName]=copy;
        refreshAct();
        return;
    }
    QMessageBox::StandardButton merge = QMessageBox::warning(this,
                                       tr("Merge Comfirmation"),
                                       tr("Are you sure to merge activities? This operation is not invokable!"),
                                       QMessageBox::Ok|QMessageBox::Cancel);
    if(merge==QMessageBox::Cancel) {
        ui->actNameEdit->setText(curActName);
        return;
    }
    activities[newActName].merge(activities[curActName]);
    activities.remove(curActName);
    curActName = newActName;
    refreshAct();
    return;
}


void Overview::on_actTypeStuWork_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(checked)
        activities[curActName].type = ActivityType(activities[curActName].type | studentWork);
    else
        activities[curActName].type = ActivityType(activities[curActName].type & nStuWorkMask);
    refreshAct();
}


void Overview::on_actTypePerDev_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(checked)
        activities[curActName].type = ActivityType(activities[curActName].type | personalDevelopment);
    else
        activities[curActName].type = ActivityType(activities[curActName].type & nPerDevMask);
    refreshAct();
}


void Overview::on_actTypeVolAct_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(checked)
        activities[curActName].type = ActivityType(activities[curActName].type | voluntaryActivity);
    else
        activities[curActName].type = ActivityType(activities[curActName].type & nVolActMask);
    refreshAct();
}


void Overview::on_actTypePracVis_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(checked)
        activities[curActName].type = ActivityType(activities[curActName].type | practiceVisit);
    else
        activities[curActName].type = ActivityType(activities[curActName].type & nPracVisMask);
    refreshAct();
}


void Overview::on_actTypeComLife_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(checked)
        activities[curActName].type = ActivityType(activities[curActName].type | communityLife);
    else
        activities[curActName].type = ActivityType(activities[curActName].type & nComLifeMask);
    refreshAct();
}


void Overview::on_actTypeAll_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(checked)
        activities[curActName].type = allType;
    else
        activities[curActName].type = noneType;
    refreshAct();
}


void Overview::on_recNewBtn_clicked()
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    QString name = QInputDialog::getText(this, tr("Name input"),tr("Input record name"));
    if(activities[curActName].records.contains(name))
        return;
    if(!name.isEmpty())
        activities[curActName].records[name]=Activity::ActivityRecord();
    refreshAct();
}


void Overview::on_recRemBtn_clicked()
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    QList<QListWidgetItem*> itemList = ui->recListWid->selectedItems();
    foreach(QListWidgetItem* item,itemList) {
        if(activities[curActName].records.contains(item->text()))
            activities[curActName].records.remove(item->text());
    }
    refreshAct();
}


void Overview::on_recListWid_itemDoubleClicked(QListWidgetItem *item)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(item->text())) {
        refreshAct();
        return;
    }
    curRecName = item->text();
    refreshAct();
    ui->actStackedWidget->setCurrentIndex(1);
}

void Overview::updateRecCheckState() {
    ui->recTypeStuWork->setCheckState(recCheckState&studentWork?Qt::Checked:Qt::Unchecked);
    ui->recTypePerDev->setCheckState(recCheckState&personalDevelopment?Qt::Checked:Qt::Unchecked);
    ui->recTypeVolAct->setCheckState(recCheckState&voluntaryActivity?Qt::Checked:Qt::Unchecked);
    ui->recTypePracVis->setCheckState(recCheckState&practiceVisit?Qt::Checked:Qt::Unchecked);
    ui->recTypeComLife->setCheckState(recCheckState&communityLife?Qt::Checked:Qt::Unchecked);
    ui->recTypeAll->setCheckState(recCheckState==allType?Qt::Checked:(recCheckState?Qt::PartiallyChecked:Qt::Unchecked));
}

void Overview::on_recTableWid_cellClicked(int row, int column)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    Activity::ActivityRecord record = activities[curActName].records[curRecName];
    QString id = ui->recTableWid->item(row,0)->text();
    if(!record.contains(id)) {
        refreshAct();
        return;
    }
    ui->creditSpBox->setValue(record[id].first);
    recCheckState = record[id].second;
    updateRecCheckState();
}


void Overview::on_recTypeStuWork_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    if(checked)
        recCheckState = ActivityType(recCheckState | studentWork);
    else
        recCheckState = ActivityType(recCheckState & nStuWorkMask);
    updateRecCheckState();
}


void Overview::on_recTypePerDev_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    if(checked)
        recCheckState = ActivityType(recCheckState | personalDevelopment);
    else
        recCheckState = ActivityType(recCheckState & nPerDevMask);
    updateRecCheckState();
}


void Overview::on_recTypeVolAct_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    if(checked)
        recCheckState = ActivityType(recCheckState | voluntaryActivity);
    else
        recCheckState = ActivityType(recCheckState & nVolActMask);
    updateRecCheckState();
}


void Overview::on_recTypePracVis_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    if(checked)
        recCheckState = ActivityType(recCheckState | practiceVisit);
    else
        recCheckState = ActivityType(recCheckState & nPracVisMask);
    updateRecCheckState();
}


void Overview::on_recTypeComLife_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    if(checked)
        recCheckState = ActivityType(recCheckState | communityLife);
    else
        recCheckState = ActivityType(recCheckState & nComLifeMask);
    updateRecCheckState();
}


void Overview::on_recTypeAll_clicked(bool checked)
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    if(checked)
        recCheckState = allType;
    else
        recCheckState = noneType;
    updateRecCheckState();
}


void Overview::on_returnBtn_clicked()
{
    ui->actStackedWidget->setCurrentIndex(0);
}


void Overview::on_paBatchAddBtn_clicked()
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }

    QStringList idNameList = ui->paIDNameEdit->toPlainText().split('\n');
    foreach(QString idName,idNameList) {
        CreditRecord rec = {ui->creditSpBox->value(),recCheckState};
        idName.replace("，",",");
        if(idName.contains(',')) {
            QStringList strlist = idName.split(',');
            if(strlist.size()!=2) continue;
            bool ok=false;
            int credit = strlist[1].toInt(&ok);
            if(ok && credit>0) rec.first = credit;
            idName = strlist[0];
        }
        if(isValidId(idName)) {
            activities[curActName].records[curRecName][idName]=rec;
        }
        else {
            foreach(Student student,students)
                if(student.name == idName)
            {
                activities[curActName].records[curRecName][student.id]=rec;
            }
        }
    }
    refreshAct();
}


void Overview::on_paRemBtn_clicked()
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    QList<QTableWidgetItem*> itemList = ui->recTableWid->selectedItems();
    QStringList idList;
    foreach(QTableWidgetItem* item,itemList)
        idList.append(ui->recTableWid->item(item->row(),0)->text());
    foreach(QString id,idList)
        if(activities[curActName].records[curRecName].contains(id))
            activities[curActName].records[curRecName].remove(id);
    refreshAct();
}


void Overview::on_paUpdBtn_clicked()
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    CreditRecord rec = {ui->creditSpBox->value(),recCheckState};
    QList<QTableWidgetItem*> itemList = ui->recTableWid->selectedItems();
    QStringList idList;
    foreach(QTableWidgetItem* item,itemList)
        idList.append(ui->recTableWid->item(item->row(),0)->text());
    foreach(QString id,idList)
        activities[curActName].records[curRecName][id]=rec;
    refreshAct();
}

void Overview::on_creditCSVBtn_clicked()
{
    QString Path = QFileDialog::getSaveFileName(this, tr("Export CSV file"), "credits.csv", tr("comma separated values (*.csv)"));
    if(Path.isEmpty()) return;
    QFile csvf(Path);
    if(!csvf.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
        QMessageBox::warning(this,tr("warning"),tr("Failed when writing to CSV file!"));
        return;
    }
    QTextStream stream(&csvf);
    stream.setEncoding(QStringConverter::System);
    stream<<tr("ID")<<","<<tr("Name")<<","<<tr("Qualification")<<","<<tr("Total")<<","
           <<tr("Student Work")<<","<<tr("Personal Development")<<","<<tr("Voluntary Activity")<<","
           <<tr("Practice and Visit")<<","<<tr("Community Life")<<Qt::endl;
    QList<Student> stuList = students.values();
    QList<Activity> actList = activities.values();
    for(int index=0;index<stuList.size();index++) {
        Student student = stuList[index];
        unsigned total = getTotalCredits(student, actList);
        categoryCreditStatus status = checkTypeStatus(student, actList);
        bool qualified = (total>=fullCredit && status.qualification()==allType);
        stream<<student.id<<","<<student.name<<","<<(qualified?tr("qualified"):tr("not qualified"))<<","<<total<<","
               <<status.stuWork<<","<<status.perDev<<","<<status.volAct<<","<<status.pracVis<<","<<status.comLife<<Qt::endl;
    }
}

void Overview::on_recNameEdit_editingFinished()
{
    if(!activities.contains(curActName)) {
        refreshAct();
        return;
    }
    if(!activities[curActName].records.contains(curRecName)) {
        refreshAct();
        return;
    }
    QString newName = ui->recNameEdit->text();
    if(newName == curRecName)
        return;
    if(newName.isEmpty()) {
        ui->recNameEdit->setText(curRecName);
        return;
    }
    if(!activities[curActName].records.contains(newName)) {
        Activity::ActivityRecord actRec = activities[curActName].records[curRecName];
        activities[curActName].records.remove(curRecName);
        curRecName = newName;
        activities[curActName].records[newName] = actRec;
        refreshAct();
        return;
    }
    QMessageBox::StandardButton merge = QMessageBox::warning(this,
                                                             tr("Merge Comfirmation"),
                                                             tr("Are you sure to merge records? This operation is not invokable!"),
                                                             QMessageBox::Ok|QMessageBox::Cancel);
    if(merge==QMessageBox::Cancel) {
        ui->recNameEdit->setText(curRecName);
        return;
    }
    foreach(QString id,activities[curActName].records[curRecName].keys())
        activities[curActName].records[newName][id] = activities[curActName].records[curRecName][id];
    activities[curActName].records.remove(curRecName);
    curRecName = newName;
    refreshAct();
    return;
}


void Overview::on_actNameQueryEdit_textChanged(const QString &arg1)
{
    ui->actListWid->clear();
    foreach(QString actName,activities.keys())
        if(actName.contains(arg1))
            ui->actListWid->addItem(actName);
}


void Overview::on_creditTableWid_itemSelectionChanged()
{
    updateRecordView();
}

void Overview::updateRecordView() {
    QList<QTableWidgetItem*> itemList = ui->creditTableWid->selectedItems();
    if(itemList.isEmpty()) {
        ui->creditTreeWid->hide();
        return;
    }
    QString ID = ui->creditTableWid->item(itemList.front()->row(),0)->text();

    QList<Activity> actList = activities.values();
    ui->creditTreeWid->clear();
    foreach(Activity activity,actList) {
        QTreeWidgetItem* activityItem = new QTreeWidgetItem({activity.name,ActivityTypeNames(activity.type).join('|')});
        bool hasRecord=false;
        foreach(QString recName,activity.records.keys()) {
            if(activity.records[recName].contains(ID)) {
                CreditRecord rec = activity.records[recName][ID];
                hasRecord = true;
                QTreeWidgetItem* recordItem = new QTreeWidgetItem({recName,
                                                                   ActivityTypeNames(ActivityType(rec.second&activity.type)).join('|'),
                                                                   QString::number(rec.first)});
                activityItem->addChild(recordItem);
            }
        }
        if(hasRecord)
            ui->creditTreeWid->addTopLevelItem(activityItem);
    }
    ui->creditTreeWid->show();
    ui->creditTreeWid->expandAll();
}

void Overview::on_creditQueryEdit_textChanged(const QString &arg1)
{
    QList<Student> stuList;
    foreach(Student student,students.values()) {
        if(student.id.contains(arg1) || student.name.contains(arg1))
            stuList.append(student);
    }
    QList<Activity> actList = activities.values();
    ui->creditTableWid->setRowCount(stuList.size());
    for(int index=0;index<stuList.size();index++) {
        Student student = stuList[index];
        ui->creditTableWid->setItem(index,0,new QTableWidgetItem(student.id));
        ui->creditTableWid->setItem(index,1,new QTableWidgetItem(student.name));
        unsigned total = getTotalCredits(student, actList);
        categoryCreditStatus status = checkTypeStatus(student, actList);
        bool qualified = (total>=fullCredit && status.qualification()==allType);
        ui->creditTableWid->setItem(index,2,new QTableWidgetItem(qualified?tr("qualified"):tr("not qualified")));
        ui->creditTableWid->setItem(index,3,new QTableWidgetItem(QString::number(total)));
        ui->creditTableWid->setItem(index,4,new QTableWidgetItem(QString::number(status.stuWork)));
        ui->creditTableWid->setItem(index,5,new QTableWidgetItem(QString::number(status.perDev)));
        ui->creditTableWid->setItem(index,6,new QTableWidgetItem(QString::number(status.volAct)));
        ui->creditTableWid->setItem(index,7,new QTableWidgetItem(QString::number(status.pracVis)));
        ui->creditTableWid->setItem(index,8,new QTableWidgetItem(QString::number(status.comLife)));
    }
    updateRecordView();
}


void Overview::on_exportActBtn_clicked()
{
    QList<QListWidgetItem*> itemList = ui->actListWid->selectedItems();
    QStringList actNameList;
    foreach(QListWidgetItem* item,itemList) {
        if(!item->text().isEmpty()&&activities.contains(item->text()))
            actNameList.append(item->text());
        else {
            refreshAct();
            return;
        }
    }
    QString Path = QFileDialog::getExistingDirectory(this,tr("Select save directory"),"");
    if(Path.isEmpty())
        return;
    foreach(QString actName,actNameList) {
        QFile ouf(Path+"/"+actName+".actrec");
        if(!ouf.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
            QMessageBox::warning(this,tr("warning"),tr("Failed while writing to activity record:")+'\n'+actName+".actrec");
        }

        QJsonDocument doc;
        doc.setObject(activities[actName].getObj());
        ouf.write(encrypt(doc.toJson(QJsonDocument::Compact)));
        ouf.close();
    }
}


void Overview::on_stuListWid_itemDoubleClicked(QListWidgetItem *item)
{
    QString ID = item->text().split(',')[0];
    if(!students.contains(ID)) {
        refreshStu();
        return;
    }
    bool ok;
    QString new_pwd = QInputDialog::getText(this,
                          tr("Password edit"),
                          tr("Input password:"),
                          QLineEdit::Normal,
                          students[ID].pwd,
                          &ok,
                          windowFlags()|Qt::FramelessWindowHint
                          );
    if(ok && new_pwd.isEmpty())
        students[ID].pwd={};
    if(ok && isValidPwd(new_pwd))
        students[ID].pwd = new_pwd;
}

